Log4Net

Log4Net是 apache 公司一款开源的日志记录组件,功能很强大,使用却很简单,本文主要讲述在 ASP.NET MVC中使用 Log4Net。本次开发环境:VS2017、 Log4Net2.0.8

安装

可以直接在 VS NuGet 中搜索 Log4Net 进行安装,也可以去官网下载相应的dll文件

Log4net配置

在安装过Log4Net后需要对项目进行一些列配置(Web.Config),下面列举两种配置方案,一种是最基本的Log4Net的配置,另外一种是更加详细的配置。

基本配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<configSections>
<!--Log4net配置-->
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
<!--Log4net配置END-->
</configSections>
<log4net>
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="test.txt"/>
<appendToFile value="true"/>
<maxSizeRollBackups value="10"/>
<maximumFileSize value="1024KB"/>
<rollingStyle value="Size"/>
<staticLogFileName value="true"/>
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/>
</layout>
</appender>
<root>
<leval value="DEBUG"/>
<appender-ref ref="RollingLogFileAppender"/>
</root>
</log4net>

进一步配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<configSections>
<!--Log4net配置-->
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
<!--Log4net配置END-->
</configSections>
<log4net>
<root>
<level value="ERROR"/>
<appender-ref ref="SysAppender"/>
</root>
<logger name="WebLogger">
<!--这里进一步限制了日志级别,只有大于等于DEBUG的时候才会记录日志-->
<level value="ERROR"/>
</logger>
<!--指定记录日志的方式,以滚动文件的方式-->
<appender name="SysAppender" type="log4net.Appender.RollingFileAppender,log4net" >
<!--指定存放日志文件的路径,这里放在App_Data路径下是为了安全-->
<param name="File" value="App_Data/" />
<!--日志以追加的方式记录-->
<param name="AppendToFile" value="true" />
<param name="RollingStyle" value="Date" />
<!--设置日志名称的生成规则-->
<param name="DatePattern" value="&quot;Logs_&quot;yyyyMMdd&quot;.txt&quot;" />
<!--日志名称是否静态:否-->
<param name="StaticLogFileName" value="false" />
<!--设置日志内容格式和布局设置-->
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
<param name="Header" value="&#13;&#10;----------------------header--------------------------&#13;&#10;" />
<param name="Footer" value="&#13;&#10;----------------------footer--------------------------&#13;&#10;" />
</layout>
</appender>
<appender name="consoleApp" type="log4net.Appender.ConsoleAppender,log4net">
<layout type="log4net.Layout.PatternLayout,log4net">
<param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n" />
</layout>
</appender>
</log4net>

需要注意:

  • <configSections></configSections> 配置节中可能有多个组件的配置,这里只显示 log4net 的配置,需要根据自身的情况进行复制,不要全盘复制上去,容易影响自身原本的配置。

  • <log4net><log4net> 配置节在 <configSections></configSections> 配置节的外部/后部。

  • 第二种配置有一个小问题未能解决:新的错误信息添加到旧的 TXT 文本中时,分割线未能正常显示,结尾线也未能正常显示。通过测试有个猜想,每次程序(网站)启动时,加载该配置,在此次程序运行中,只加载一次分割线,用于区分与上次程序运行时产生的异常信息,此次程序运行中后来的异常信息则不再添加分割线。如果你有其他的配置能解决这个问题或其他想法欢迎在下方留言一起讨论、学习!

初始化程序

在程序最开始的时候加入:

1
log4net.Config.XmlConfigurator.Configure();

项目用的是 ASP.MVC ,所以添加在了 Global.asax 文件中的 Appliction_Start() 方法中。

编写此行代码需要引入 log4net 的命名空间 using log4net;

打印日志信息

基本使用

在需要打印日志的地方添加:

1
LogManager.GetLogger(typeof(Program)).Debug("信息");

通过 LogManager.GetLogger 传递需要记录的日志类名获得这个类的 ILog (这样在日志文件中就能看到这条日志是哪个类输出的了),然后调用 Debug 方法输出消息。因为一个类内部不止一个地方要打印日志,所以 一般把 ILog 声明为一个 static 字段:

1
Private static ILog logger = LogManager.GetLogger(typeof(Test))

输出错误消息用 ILog.Error 方法,第二个参数可以传递 Exception 对象,如:

log.Error("***错误"+ex)log.Error("***错误",ex)

生产者——消费者模式

上面基本使用有一个问题,如果是网站类或大型系统,是很多人同一时间点进行使用,但是每次写入文件的日志信息可能就会有很多条,同一时间内多条日志同时写入文本就会造成 文件并发 问题。这里通过队列的方式来记录日志。

思路:把所有产生的日志信息存放到一个队列里面,然后通过新建一个线程不断的从这个队列里面读取异常信息,然后往日志文件里面写。这个时候就不用担心多个日志信息同时写入日志文件引起的文件并发问题,这就是所谓的生产者——消费者模式。

新建异常信息监控类

新建一个类 MyErrorAttribute ,继承自全局异常类 HandleErrorAttribute。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace SpringLog4netDemo.Models
{

public class MyErrorAttribute:HandleErrorAttribute
{
//创建静态队列
public static Queue<Exception> ExceptionQueue = new Queue<Exception>();
public override void OnException(ExceptionContext filterContext)
{
//将异常信息写入队列中
ExceptionQueue.Enqueue(filterContext.Exception);
base.OnException(filterContext);
}

}
}

这样做的目的是通过修改全局异常类拿到触发异常的信息,存储到我们准备好的队列中,用于后面的存储。

在 FilterConfig 类中注册自己的异常信息监控类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System.Web;
using System.Web.Mvc;
using SpringLog4netDemo.Models;

namespace SpringLog4netDemo
{
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// filters.Add(new HandleErrorAttribute());
filters.Add(new MyErrorAttribute());
}
}
}

在 App_Start 文件夹下 有三个类 ,修改其中的 FilterConfig.cs ,将我们自己写的异常信息监控类注入。

在程序入口添加线程监控

在 Global.asax 文件中的 Application_Start() 方法中添加一个线程,用于监控程序运行过程中是否有异常发生。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

//新建线程用以检测日志
ThreadPool.QueueUserWorkItem(o =>
{
while (true)
{
if (MyErrorAttribute.ExceptionQueue.Count > 0)
{
Exception ex = MyErrorAttribute.ExceptionQueue.Dequeue();
if (ex != null)
{
ILog logger = LogManager.GetLogger("ErrorMsg");
logger.Error(ex.ToString());
}
else
{
Thread.Sleep(500);
}
}
else
{
Thread.Sleep(500);
}
}
});

添加引发异常的方法进行测试

在控制器 Home 中故意添加一个引发一场的 Action 的方法 TestLog 进行测试。

1
2
3
4
5
6
7
public ActionResult TestLog()
{
int a = 5;
int b = 0;
int c = a / b;
return View();
}

在浏览器进行测试:

打开项目所在目录下的 App_Data文件夹

打开项目所在目录下的 App_Data文件夹,可以看到已经有一个日志文件了:

打开该文件可以看到日志信息已经保存进去

需要注意的地方

在浏览器直接请求http://localhost:5252/home/testlog 时,VS会报错暂停,这个时候程序已经中断,但是还并未走到我们新注册的异常信息监控类里面的方法,也就是说异常信息还并未存到队列并且并未存储到本地。

此时VS的页面是这样的:

这个时候不要勾选 “SpringLog4netDemo.dll” 前面的选择框,勾选的话以后在此项目中的此类异常都会被VS屏蔽不再显示,在单独测试 Log4Net 的项目中,这个无所谓,但是如果是比较大的项目的话,这样就比较麻烦了,这个时候直接点击 继续 就可以继续运行了,或者有兴趣的话可以执行下一步查看程序执行的流程。

如果手滑点到那里了怎么办呢?

打开 调试 > 窗口 > 异常设置 > 选中全部选项 > 检查所有选项中是否有屏蔽条件 > 删除屏蔽条件

Log4Net相关概念

Log4Net 有3个重要的组件:loggers , appenders 和 layouts 。这3个组件协同工作使得开发者能够根据信息类型和级别(Level)记录信息,以及在运行时控制信息的格式化和信息的写入位置(如:控制台、文件、内存、数据库等)过滤器帮助这些组件控制追加器 (appender)的行为和把对象转化成字符串的对象渲染。

Appender:可以寄那个日志输出到不同的地方,不同的输出目标对应不同的 Appender,如 RollingFileAppender(滚动文件)、AdoNetAppender(数据库)、SmtpAppender(邮件)等。

level(级别):标识这条日志信息的重要级别。None > Fatal > ERROR > WARN > DEBUG > INFO >ALL ,设定一个 Level ,那么低于这个 Level 的日志是不会被写入到 Appender 中的。

Log4Net 还可以设定多个 Appender,可以实现同时将日志记录到文件、数据库、发送邮件等;可以设定不同Appdener 的不同 level ,可以实现普通级别都记录到文件、ERROR以上级别都发送邮件;可以实现对不同的类设定不同的 Appender;还可以自定义 Appender ,自己实现将 ERROR 信息发送短信等。

日志框架除了 Log4Net 外,还有 Enterprise Libray 中的 Logging Application Block、Apache 的 CommonLog 以及 NLog 等,使用起来都差不多。

最后附上 Log4Net 的官方文档链接